module iic1(
clk_sys,//系统时钟
rst_n,//系统复位
eeprom_scl,//eeprom串行时钟信号
eeprom_sda,//eeprom 串行数据信号
key_wr, //外部写控制按键
key_rd,//外部读控制按键
result,//数据采集结果寄存器
led    //led指示灯
);
input clk_sys;
input rst_n;
input key_rd;
input key_wr;

reg clk;
output reg eeprom_scl;
inout eeprom_sda;
output reg led;
reg [7:0]cnt;     //分频计数器
reg [7:0]state;   //状态寄存器
reg [3:0]counter; //数据位移计数器
reg link_sda;     //总线开关
reg wr;           //写标志寄存器
reg rd;           //读标志寄存器
reg sda_buf;      //总线缓冲寄存器
output reg [7:0]result;
reg [7:0]data;        //待发送控制字、地址、数据寄存器
assign eeprom_sda =(link_sda)?sda_buf:1'hz;

//-------------------system clk----------------
//系统时钟分频
always @(posedge clk_sys or negedge rst_n)
	begin
		if(!rst_n)
			begin
					clk<=0;
					cnt<=0;
			end
		else
			begin
				if(cnt<250)
					cnt<=cnt+1'b1;
				else
					begin
						clk<=~clk;
						cnt<=0;
					end
			end
	end
//--------------eeprom scl----------------
//产生eeprom scl 信号
always @(negedge clk or negedge rst_n)
	begin
		if(!rst_n)
			eeprom_scl<=0;
		else
			eeprom_scl<=~eeprom_scl;
	end	
//-----------------eeprom contral---------
always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)//所有寄存器复位
			begin
				state<=0;
				link_sda<=0;
				sda_buf<=0;
				counter<=0;
				wr<=0;
				led<=1;
				rd<=0;
				result<=0;
				data<=0;
			end
		else
			begin
				case(state)
				//发送start信号
				0:begin
						if(!key_wr)
							wr<=1;
						if(!key_rd)
							rd<=1;
							
						if(((rd==1)||(wr==1)&&(!eeprom_scl)))
						begin
							link_sda<=1;
							sda_buf<=1;
							state<=1;
						end
					end
				1:begin
					if(eeprom_scl)//高电平期间使sda,使sda由高变低，启动串行传输
						begin
							sda_buf<=0;
							state<=2;
							data<=8'b10100000;//写控制字
						end
					end
				//发送写控制字，并转串
				2:begin
						if((counter<8)&&(!eeprom_scl))
						//在scl 低电平期间，完成串并转换，发送写控制字
							begin
								counter<=counter+1'b1;
								data<={data[6:0],data[7]};
								sda_buf<=data[7];
							end
						else if((counter==8)&&(!eeprom_scl))
							begin
								counter<=0;
								state<=3;
								link_sda<=0;//FPGA释放总线控制权
							end
					end
				//接收应答信号
				3:begin
					if(eeprom_scl)
					//在scl高电平期间，监测是否有应答信号(sda为低电平)
						if(!eeprom_sda)
							begin
								state<=4;
								data<=8'b00000000;//高字节地址准备
							end
						end
				//发送高字节地址
				4:begin
					link_sda<=1;//FPGA 控制总线
					if((counter<8)&&(!eeprom_scl))
					//在scl低电平期间完成并转串，发出高字节地址
						begin
							counter<=counter+1'b1;
							data<={data[6:0],data[7]};
							sda_buf<=data[7];
						end
					else if((counter==8)&&(!eeprom_scl))
						begin
							counter<=0;
							state<=5;
							link_sda<=0;//FPGA释放总线控制权
						end
					end
				//接收应答信号
				5:begin
					if(eeprom_scl)
					//在scl高电平期间，监测是否有应答信号(sda为低电平)
						if(!eeprom_sda)
						//eeprom_sda为低电平时，有应答信号，跳转状态
							begin
								state<=6;
								data<=8'b00000000;//高字节地址准备
							end
						end
				//发送低字节地址
				6:begin
					link_sda<=1;
					//FPGA控制总线
					if((counter<8)&&(!eeprom_scl))
					//在scl低电平期间，完成并转串，发出高字节地址
					begin
						counter<=counter+1'b1;
						data<={data[6:0],data[7]};
						sda_buf<=data[7];
					end
					else if((counter==8)&&(!eeprom_scl))
						begin
							counter<=0;
							state<=7;
							sda_buf<=1;
							link_sda<=0;//释放总线
						end
					end
//接收ack信号
			7:begin
				if(eeprom_scl)
				//在scl高电平期间，检测是否有应答信号
				begin
					if(!eeprom_sda)
					begin
					if(wr==1)
						//如果是写，跳转到状态8，遵循随机写时序
						state<=8;
					if(rd==1)
						//读时序，跳到状态11
						begin
							state<=11;
							sda_buf<=1;
							//准备再次发启动信号
						end
					data<=8'b00001111;
					//准备写入的数据
				  end
			end
	end

	//接收有效数据
	8:begin 
		link_sda<=1;
		if((counter<8)&&(!eeprom_scl))
		//在scl低电平期间，完成并转串，发出有效数据
			begin
				counter<=counter+1'b1;
				data<={data[6:0],data[7]};
				sda_buf<=data[7];
			end
		else if((counter==8)&&(!eeprom_scl))
			begin
				counter<=0;
				state<=9;
				link_sda<=0;
			end
	end
	
					//接收应答信号
				9:begin
					if(eeprom_scl)
						begin
					//在scl高电平期间，监测是否有应答信号(sda为低电平)
						if(!eeprom_sda)
							state<=10;
						
						end
					end
				//发送停止信号
				10:begin
				link_sda<=1;
				//fpgA控制总线
				sda_buf<=0;
				if(eeprom_scl)
				//在scl高电平期间，拉高sda，终止串行传输
					begin 
					 led<=0;//点亮led，说明写操作完毕
					 sda_buf<=1;
					 if(key_wr && key_wr)
					//在按键放开以后才跳转回空闲状态，避免不断循环写入
						state<=0;//状态跳回
						wr<=0;//清除写标志位
					end
				end
				11:begin
					link_sda<=1;//FPGA控制总线
					if(eeprom_scl)////scl高电平期间拉低sda,发送启动信号
					begin 
						sda_buf<=0;
						state<=12;
						data<=8'b10100001;//读控制字
					end
				end
			//发送控制字
			12:begin
				if((counter<8)&&(!eeprom_scl))
				begin
					counter<=counter+1'b1;
					data<={data[6:0],data[7]};
					sda_buf<=data[7];
				end
				else if((counter==8)&&(!eeprom_scl))
					begin 
						counter<=0;
						state<=13;
						link_sda<=0;
					end
				end
//接收ack信号
		13:begin
			if(eeprom_scl)//在scl高电平期间，检测是否有应答信号
				begin
					if(!eeprom_sda)//有应答则状态继续跳转
						state<=14;
				end
			end
//接收输入的有效数据	
			14:begin
				if((counter<8)&&(eeprom_scl))//在scl高电平期间
				begin
					counter<=counter+1'b1;
					result[7-counter]<=eeprom_sda;
				end
			else if(counter==8)
				begin
					counter<=0;
					state<=15;
					sda_buf<=1;
					link_sda<=1;
				end
			end
		//发送NO ACK信号
		15:begin
			if(eeprom_scl)
			//在scl高电平期间，将sda总线拉高，发出非应答信号
			begin 
				sda_buf<=1;
				state<=16;
			end
		end
	//发送停止信号
	16:begin
		if(!eeprom_scl)
		//在scl低电平期间，将sda总线拉低，准备发送停止信号
			begin
				sda_buf<=1;//拉高sda
				state<=0;//状态回转
				rd=0;//清除读标志信号
			end
		end
	default:state<=0;
	endcase
end
end
endmodule

	